<template>
  <div class="app-single-upload" :class="{ 'app-has-img': imageUrl }">
    <el-space direction="vertical" alignment="left">
      <el-upload :on-error="uploadError" :action="uploadUrl" accept="image/jpeg,image/jpeg,image/png" :limit="1" list-type="picture-card" :on-preview="handlePreview" :on-success="handleUploadSuccess" :before-upload="beforeAvatarUpload" :on-remove="handleRemove">
        <Icon name="ep:plus" style="font-size: 60px" />
      </el-upload>
      <div class="el-upload__tip text-red-400 mt-0">
        <Icon name="carbon:help" class="relative mt--1" />
        <slot name="tip" />
      </div>
    </el-space>
    <el-image-viewer v-if="dialogVisible" crossorigin="anonymous" :url-list="[imageUrl]" @close="imageView" />
  </div>
</template>
<script setup lang="ts">
import { ElNotification } from 'element-plus'
import type { UploadProps } from 'element-plus'
import { set } from '@vueuse/core'

interface UploadFileProps {
  imageUrl: string // 图片地址 ==> 必传
  id?: string // 组件id ==> 非必传，当页面存在多个上传组件时必传（默认为upload）
  drag?: boolean // 是否支持拖拽上传 ==> 非必传（默认为true）
  disabled?: boolean // 是否禁用上传组件 ==> 非必传（默认为false）
  fileSize?: number // 单个文件大小限制 ==> 非必传（默认为 2M）
  uploadStyle?: { [key: string]: any } // 上传组件样式 ==> 非必传
}

const props = withDefaults(defineProps<UploadFileProps>(), {
  id: 'upload',
  drag: true,
  disabled: false,
  fileSize: 2,
  uploadStyle: () => ({ width: '175px', height: '175px' }),
})

interface UploadEmits {
  (e: 'update:imageUrl', value: string): void
  (e: 'check-validate'): void
}
const emit = defineEmits<UploadEmits>()
const apiUrl = import.meta.env.VITE_API_URL
const uploadUrl = `${apiUrl}api/file/upload`
const imageUrl = ref('')
const dialogVisible = ref(false)

// 上传成功
const handleUploadSuccess: UploadProps['onSuccess'] = (_, uploadFile: any) => {
  const path = uploadFile.response?.data?.path
  const uploadPath = `${apiUrl + path}`

  set(imageUrl, uploadPath)
  emit('update:imageUrl', uploadPath)
  handleNotice('图片上传成功！', 'success')
}

// 上传前
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
  const imgType = ['image/jpg', 'image/jpeg', 'image/png']

  if (!imgType.includes(rawFile.type)) {
    handleNotice('上传图片必须是 JPG/JPEG/PNG 格式！')
    return false
  } else if (rawFile.size / 1024 / 1024 > props.fileSize) {
    handleNotice(`上传图片大小不能超过 ${props.fileSize}MB！`)
    return false
  }

  return true
}

// 温馨提示
const handleNotice = (message: string, type: any = 'warning'): void => {
  ElNotification({
    title: '温馨提示',
    message,
    type,
  })
}

// 删除图片
const handleRemove: UploadProps['onRemove'] = (file, uploadFiles) => {
  console.log(file, uploadFiles)
  set(imageUrl, '')
  emit('update:imageUrl', '')
}

// 预览
const handlePreview = (uploadFile: any) => {
  if (!uploadFile.response?.data?.path) {
    handleNotice('图片上传失败，请您稍候在试！', 'error')
    return
  }

  const url = `${apiUrl}${uploadFile.response?.data?.path}`

  set(imageUrl, url)
  set(dialogVisible, true)
}

const imageView = () => {
  set(dialogVisible, !dialogVisible.value)
}

// 图片上传错误提示
const uploadError = () => {
  handleNotice('图片上传失败，请您重新上传！', 'error')
}
</script>
<style lang="scss">
.avatar-uploader .el-upload {
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
}

.avatar-uploader .el-upload:hover {
  border-color: var(--el-color-primary);
}

.el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  text-align: center;
}
.app-has-img {
  .el-upload {
    display: none;
  }
}
.app-single-upload {
  .el-space__item {
    padding-bottom: 0 !important;
  }
}
</style>
